﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using NUnit.Framework;

namespace Calais.UnitTests
{
    [TestFixture]
    public class RDFSTests
    {
        private string _apiKeyPath;
        private string _testTextPath;
        private string _preProcessed;
        private CalaisRdfDocument _calaisDocument;

        [SetUp]
        public void Setup()
        {
            // read API key from file on desktop
            _apiKeyPath = Environment.GetEnvironmentVariable("USERPROFILE") + @"\Desktop\CalaisApiKey.txt";
            _testTextPath = Environment.GetEnvironmentVariable("USERPROFILE") + @"\Desktop\CalaisTest.txt";
            _preProcessed = File.ReadAllText(@"..\..\Output.xml");
            _calaisDocument = CalaisDotNet.Parse<CalaisRdfDocument>(_preProcessed);
        }

        [Test]
        public void CheckInterface_Can_Cast_And_Set_On_Base()
        {
            var ann = new CalaisAnniversary();
            ann.Name = "National Horse Day";

            var company = new CalaisCompanyDisambiguated();
            company.Name = "Company1";
            company.Subject = ann;

            Assert.AreEqual("National Horse Day", company.Subject.Name);
            company.Subject.Name = "National Cat Day";

            var ann2 = (CalaisAnniversary)company.Subject;
            Assert.AreEqual("National Cat Day", ann2.Name);
        }

        [Test]
        public void GetEntities_Simple_Entity()
        {
            var results = (from item in _calaisDocument.GetEntities<CalaisPerson>()
                           where item.Name.Contains("Brown")
                           select item).ToList();

            Assert.AreEqual(2, results.Count); //Des Browne + Grodon Brown

            foreach (var result in results)
            {
                Assert.IsTrue(result.Name.Contains("Brown"));

                Console.WriteLine(result.Name);
                Console.WriteLine(result.Nationality);
                Console.WriteLine(result.PersonType);
            }
        }

        [Test]
        public void GetEntities_DisambiguatedEntity()
        {
            var results = (from item in _calaisDocument.GetEntities<CalaisCountryDisambiguated>()
                           select item).ToList();

            Assert.AreEqual(2, results.Count); //UK + Afghanistan

            foreach (var result in results)
            {
                Console.WriteLine(result.ContainedByCountry);
                Console.WriteLine(result.Latitude);
                Console.WriteLine(result.Longitude);
                Console.WriteLine(result.Name);
                Console.WriteLine(result.ShortName);

                Assert.IsNotNull(result.Subject);
                Assert.AreEqual(typeof(CalaisCountry), result.Subject.GetType());

                Console.WriteLine(result.Subject.Name);
            }
        }

        [Test]
        public void GetEntities_Relationship()
        {
            var results = (from item in _calaisDocument.GetEntities<CalaisPersonCareer>()
                           select item).ToList();

            Assert.AreEqual(3, results.Count);

            foreach (var result in results)
            {
                if (result.Organization != null)
                {
                    Assert.AreEqual(typeof(CalaisOrganization), result.Organization.GetType());
                    Console.WriteLine(result.Organization.Name);
                }
                if (result.CareerType != null)
                {
                    Console.WriteLine(result.CareerType);
                }
                if (result.City != null)
                {
                    Assert.AreEqual(typeof(CalaisCity), result.City.GetType());
                    Console.WriteLine(result.City.Name);
                }
                if (result.Company != null)
                {
                    Assert.AreEqual(typeof(CalaisCompany), result.Company.GetType());
                    Console.WriteLine(result.Company.Name);
                }
                if (result.Country != null)
                {
                    Assert.AreEqual(typeof(CalaisCountry), result.Country.GetType());
                    Console.WriteLine(result.Country.Name);
                }
                if (result.Person != null)
                {
                    Assert.AreEqual(typeof(CalaisPerson), result.Person.GetType());
                    Console.WriteLine(result.Person.Name);
                }
                if (result.Position != null)
                {
                    Console.WriteLine(result.Position.Name);
                }
                if (result.ProvinceOrState != null)
                {
                    Console.WriteLine(result.ProvinceOrState.Name);
                }
                if (result.Status != null)
                {
                    Console.WriteLine(result.Status);
                }
            }
        }

        [Test]
        public void GetEntities_Can_Create_CustomType_from_String_Literal()
        {
            var results = (from item in _calaisDocument.GetEntities<CalaisManMadeDisaster>()
                           select item).ToList();

            Assert.AreEqual(3, results.Count);

            foreach (var result in results)
            {
                if (result.Date != null)
                {
                    Console.WriteLine("Date : " + result.Date);
                }
                if (result.DateString != null)
                {
                    Console.WriteLine("DateString : " + result.DateString);
                }
                if (result.Facility != null)
                {
                    Assert.AreEqual(typeof(CalaisFacility), result.Facility.GetType());
                    Console.WriteLine("Facility : " + result.Facility.Name);
                }
                if (result.Location != null)
                {
                    Assert.AreEqual(typeof(CalaisCustomLocation), result.Location.GetType());
                    Console.WriteLine("Location : " + result.Location.Name);
                }
                if (result.ManmadeDisaster != null)
                {
                    Console.WriteLine("ManMade : " + result.ManmadeDisaster);
                }
            }
        }

        [Test]
        public void Print_All_Document_Entities()
        {
            var res1 = from item in _calaisDocument.Entities
                       select item;

            foreach (var result in res1)
            {
                Console.WriteLine("Type: " + result.EntityType);

                Console.WriteLine(_calaisDocument.GetEntityById(result.Id).ListProperties(" => ", false));
 
                Console.WriteLine("--------------------------------------");
            }

        }

        [Test]
        public void Print_All_Document_Relationships()
        {
            var res2 = from item in _calaisDocument.Relationships
                       select item;

            foreach (var result in res2)
            {
                Console.WriteLine("Type: " + result.RelationshipType);

                Console.WriteLine(_calaisDocument.GetEntityById(result.Id).ListProperties(" => ", false));

                Console.WriteLine("--------------------------------------");
            }
        }
    }

    public static class EntityHelpers
    {
        public static string ListProperties(this object obj, string seperator, bool subtype)
        {
            var sb = new StringBuilder();

            var results = from item in obj.GetType().GetProperties()
                          select new { Name = item.Name, Value = item.GetValue(obj, null) };

            foreach (var result in results)
            {
                if (result.Value == null) continue;

                if(result.Value.GetType().GetCustomAttributes(typeof(CalaisTypeAttribute), false).Count() > 0)
                {
                    sb.AppendLine("==> Sub Type: " + result.Value.GetType().Name);
                    sb.Append(result.Value.ListProperties(seperator, true));        
                }
                else
                {
                    if (subtype)
                    {
                        sb.AppendLine("==> " + result.Name + seperator + result.Value);
                    }
                    else
                    {
                        sb.AppendLine(result.Name + seperator + result.Value);
                    }
                }
            }

            return sb.ToString();
        }
    }
}
